from random import uniform
from scipy.stats import expon, weibull_min, norm, lognorm, uniform, binom


class Distribution():
    """
       概率分布类，用于构造概率分布对象

    """

    def __init__(self, disttype, args):
        """
            概率分布类

            Args：
            self：节点信息
            disttype：概率分布类型
            args：分布参数

            Return：无

        """
        self.disttype = disttype
        self.args = [float(x) for x in args]

    def cdf(self, time):
        pass

    def inverse_cdf(self, probability):
        pass


class Exponential(Distribution):

    def __init__(self, disttype, args):
        super(Exponential, self).__init__(disttype, args)
        self.scale = 1 / self.args[0]

    def cdf(self, time):
        return expon.cdf(time, 0, self.scale)

    def inverse_cdf(self, probability):
        return expon.ppf(probability, 0, self.scale)

class Dirac(Distribution):
    def __init__(self,disttype,args):
        super(Dirac,self).__init__(disttype,args)
        self.timelength = args[0]

    def inverse_cdf(self,prob):
        return self.timelength


class Normal(Distribution):

    def __init__(self, disttype, args):
        super(Normal, self).__init__(disttype, args)
        self.loc = self.args[0]
        self.scale = self.args[1]

    def cdf(self, time):
        return norm.cdf(time, self.loc, self.scale)

    def inverse_cdf(self, probability):
        if probability < self.cdf(0):  # 避免返回小于0的时间
            return 0
        else:
            return norm.ppf(probability, self.loc, self.scale)


class LogNormal(Distribution):

    def __init__(self, disttype, args):
        super(LogNormal, self).__init__(disttype, args)
        #self.shape = self.args[0]
        self.loc = self.args[0]
        self.scale = self.args[1]

    def cdf(self, time):
        return lognorm.cdf(time, self.loc, self.scale)

    def inverse_cdf(self, probability):
        return lognorm.ppf(probability, self.loc, self.scale)


class Weibull(Distribution):

    def __init__(self, disttype, args):
        super(Weibull, self).__init__(disttype, args)
        if len(args) == 2:
            self.scale = args[0]
            self.shape = args[1]
            self.loc = 0
        elif len(args)==3:
            self.scale = args[0]
            self.shape = args[1]            
            self.loc = args[2]

    def cdf(self, time):
        return weibull_min.cdf(time, self.shape, loc=self.loc, scale = self.scale)

    def inverse_cdf(self, probability):
        return weibull_min.ppf(probability, self.shape, loc=self.loc, scale = self.scale)


class Uniform(Distribution):

    def __init__(self, disttype, args):
        super(Uniform, self).__init__(disttype, args)
        self.loc = self.args[0]
        self.upper_bound = self.args[1]
        self.scale = self.upper_bound - self.loc

    def cdf(self, time):
        return uniform.cdf(time, self.loc, self.scale)

    def inverse_cdf(self, probability):
        return uniform.ppf(probability, self.loc, self.scale)


class Fixed(Distribution):

    def __init__(self, disttype, args):
        super(Fixed, self).__init__(disttype, args)
        self.p = args[0]

    def cdf(self):
        pass

    def inverse_cdf(self, probability):
        pass


class Binomial(Distribution):

    def __init__(self, disttype, args):
        super(Binomial, self).__init__(disttype, args)
        self.n = args[0]
        self.k = args[1]
        self.p = args[2]       

    def cdf(self):
        return binom.cdf(self.k,self.n,self.p)

    def inverse_cdf(self, probability):
        pass

class SoF(Distribution):

    def __init__(self, disttype, args):
        super(SoF, self).__init__(disttype, args)
        self.p = args[0]
        self.n = args[1]#使用次数
        self.m = args[2]#允许失败的次数

    def cdf(self):
        pass

    def inverse_cdf(self, probability):
        pass